package com.wanglianyun.aspect;

import com.wanglianyun.config.datasource.DynamicDataSourceContextHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.FieldSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Description:
 * Copyright: Copyright (c) 2024
 * Create Time: 2024-11-15 14:36
 *
 * @author wanglianyun
 */
@Component
@Aspect
public class ReplaceAspect {

    /**
     * 对加上ReplaceVarify注解的方法进行前置处理
     * 解释：@annotation后面有两种写法
     * 写法一：直接加上注解的全路径名，例如@annotation(com.wanglianyun.aspect.ReplaceVarify)，另外replace方法里不加注解类作为请求参数
     * 写法二：直接放replace的注解请求参数，例如@annotation(replaceVarify)，前提是请求参数里要有ReplaceVarify注解类replaceVarify作为请求参数，
     * 方法二的好处是直接可以利用方法传入的注解参数进行获取注解的属性，不需要再进行代码的转换处理，而方法一如果想获取注解的相关属性则需要自己转换，
     * 比如通过     Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
     *             ReplaceVarify annotation = method.getAnnotation(ReplaceVarify.class);
     * 注意：@Around环绕通知与ProceedingJoinPoint联用，@Before不能与ProceedingJoinPoint联用
     */
    @Before("@annotation(replaceVarify)")
    public void replace(JoinPoint joinPoint, ReplaceVarify replaceVarify) {
        //获取方法的请求参数
        Object[] args = joinPoint.getArgs();
        System.out.println(joinPoint.getSignature().getName() + "方法的请求参数个数为：" + args.length);
        if (args == null) {
            return;
        }
        //obj代表方法的请求类,方法有三个请求类就是循环三次，一般请求体只有一个
        Arrays.stream(args).forEach(obj -> validateFields(obj));
    }

    private void validateFields(Object obj) {
        // 对请求类里带有Replace注解的字段进行过滤
        List<Field> fieldsWithReplaceAnnotationList = Arrays.stream(obj.getClass().getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(Replace.class))
                .collect(Collectors.toList());

        for (Field field : fieldsWithReplaceAnnotationList) {
            //统一对带有Replace注解的字段进行处理
            dealFieldValue(obj, field);
        }
    }

    private void dealFieldValue(Object obj, Field field) {
        //通过反射进行获取字段并处理
        try {
            //对需要修改的字段先设置可见性
            field.setAccessible(true);
            //获取字段上Replace注解
            Replace replace = field.getAnnotation(Replace.class);
            //获取注解的参数
            String source = replace.source();
            String target = replace.target();
            String s = String.valueOf(field.get(obj));
            String replaceStr = s.replace(target, source);
            //重新设置字段的值
            field.set(obj, replaceStr);
            // 字段属性修改后重新设回不可见
            field.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
